<!doctype html>
<html lang="zh"><head>
<title>vue-事件绑定原理 - 糖羽仙</title>
<meta charset="UTF-8">
<meta name="keywords" content="blog ACG JavaScript VUE IT">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">

<link rel="shortcut icon" href="/images/head/head.jpg" type="image/jpeg" />
<meta name="description" content="Vue中通过v-on或其语法糖@指令来给元素绑定事件并且提供了事件修饰符">
<meta property="og:type" content="article">
<meta property="og:title" content="vue-事件绑定原理">
<meta property="og:url" content="https://www.tangyuxian.com/2021/03/02/%E5%89%8D%E7%AB%AF/vue/vue-%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86/index.html">
<meta property="og:site_name" content="糖羽仙">
<meta property="og:description" content="Vue中通过v-on或其语法糖@指令来给元素绑定事件并且提供了事件修饰符">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-03-02T05:59:23.000Z">
<meta property="article:modified_time" content="2022-08-20T10:06:06.032Z">
<meta property="article:author" content="tangyuxian">
<meta property="article:tag" content="vue">
<meta name="twitter:card" content="summary">

<link rel="stylesheet" href="/lib/fancybox/fancybox.css">
<link rel="stylesheet" href="/lib/mdui_043tiny/mdui.css">


<link rel="stylesheet" href="/lib/iconfont/iconfont.css?v=1763992124194">

    <link rel="stylesheet" href="//at.alicdn.com/t/font_2421060_8z08qcz5sq3.css">

<link rel="stylesheet" href="/css/style.css?v=1763992124194">




    
        <link rel="stylesheet" href="/custom.css?v=1763992124194">
    
        <link rel="stylesheet" href="/themes/umaru/index.css?v=1763992124194">
    
        <link rel="stylesheet" href="/themes/asuka/index.css?v=1763992124194">
    



<script src="/lib/mdui_043tiny/mdui.js" async></script>
<script src="/lib/fancybox/fancybox.umd.js" async></script>
<script src="/lib/lax.min.js" async></script>


<script async src="/js/app.js?v=1763992124194"></script>

 

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-1Z7TFL96ZH"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-1Z7TFL96ZH');
</script>


<link rel="stylesheet"  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/atom-one-dark.min.css">
<!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-shiki-plugin@latest/lib/codeblock.css">
<style>:root{--hl-color:#e1e4e8;--hl-bg:#24292e;--hltools-bg:#1f2428;--hltools-color:#c5c5c5;--hlnumber-bg:#24292e;--hlnumber-color:#444d56;--hlscrollbar-bg:#32383e;--hlexpand-bg:linear-gradient(180deg,rgba(36,41,46,0.1),rgba(36,41,46,0.9))}</style><!-- hexo injector head_end end --><meta name="generator" content="Hexo 7.3.0"></head><body class="nexmoe mdui-drawer-body-left"><div id="nexmoe-background"><div class="nexmoe-bg" style="background-image: url(/images/background/xiaomai.jpg)"></div><div class="nexmoe-character"></div><div class="mdui-appbar mdui-shadow-0"><div class="mdui-toolbar"><a class="mdui-btn mdui-btn-icon mdui-ripple" mdui-drawer="{target: &#039;#drawer&#039;, swipe: true}" title="menu"><i class="mdui-icon nexmoefont icon-menu"></i></a><div class="mdui-toolbar-spacer"></div><a class="mdui-btn mdui-btn-icon" href="/" title="tangyuxian"><img src="/images/head/head.jpg" alt="tangyuxian"></a></div></div></div><div id="nexmoe-header"><div class="nexmoe-drawer mdui-drawer" id="drawer">
    <div class="nexmoe-avatar mdui-ripple">
        <a href="/" title="tangyuxian">
            <img src="/images/head/head.jpg" alt="tangyuxian" alt="tangyuxian">
        </a>
    </div>
    <div class="nexmoe-count">
        <div class="nexmoe-count-item"><span>文章</span>84 <div class="item-radius"></div><div class="item-radius item-right"></div> </div>
        <div class="nexmoe-count-item"><span>标签</span>38<div class="item-radius"></div><div class="item-radius item-right"></div></div>
        <div class="nexmoe-count-item"><span>分类</span>5<div class="item-radius"></div><div class="item-radius item-right"></div></div>
    </div>
    <div class="nexmoe-list mdui-list" mdui-collapse="{accordion: true}">
        
        <a class="nexmoe-list-item mdui-list-item mdui-ripple false" href="/" title="回到首页">
            <i class="mdui-list-item-icon nexmoefont icon-meishi"></i>
            <div class="mdui-list-item-content">
                回到首页
            </div>
        </a>
        
        <a class="nexmoe-list-item mdui-list-item mdui-ripple false" href="/archives.html" title="文章归档">
            <i class="mdui-list-item-icon nexmoefont icon-hanbao1"></i>
            <div class="mdui-list-item-content">
                文章归档
            </div>
        </a>
        
        <a class="nexmoe-list-item mdui-list-item mdui-ripple false" href="/about.html" title="关于糖糖">
            <i class="mdui-list-item-icon nexmoefont icon-jiubei1"></i>
            <div class="mdui-list-item-content">
                关于糖糖
            </div>
        </a>
        
        <a class="nexmoe-list-item mdui-list-item mdui-ripple false" href="/friend.html" title="我的朋友">
            <i class="mdui-list-item-icon nexmoefont icon-cola"></i>
            <div class="mdui-list-item-content">
                我的朋友
            </div>
        </a>
        
    </div>
    
    
        
        <div class="nexmoe-widget-wrap">
    <div class="nexmoe-widget nexmoe-search">
         
            <form id="search_form" action_e="https://cn.bing.com/search?q=site:tangyuxian.com" onsubmit="return search();">
                <label><input id="search_value" name="q" type="search" placeholder="搜索"></label>
            </form>
         
    </div>
</div>




    
        
        <div class="nexmoe-widget-wrap">
	<div class="nexmoe-widget nexmoe-social">
		<a
			class="mdui-ripple"
			href="http://wpa.qq.com/msgrd?v=3&uin=2120252100&site=qq&menu=yes"
			target="_blank"
			mdui-tooltip="{content: 'QQ'}"
			style="
				color: rgb(64, 196, 255);
				background-color: rgba(64, 196, 255, .1);
			"
		>
			<i
				class="nexmoefont icon-QQ"
			></i> </a
		><a
			class="mdui-ripple"
			href="mailto:tangyuxian@vip.qq.com"
			target="_blank"
			mdui-tooltip="{content: 'mail'}"
			style="
				color: rgb(249,8,8);
				background-color: rgba(249,8,8,.1);
			"
		>
			<i
				class="nexmoefont icon-mail-fill"
			></i> </a
		><a
			class="mdui-ripple"
			href="https://blog.csdn.net/qq_40621378?type=blog"
			target="_blank"
			mdui-tooltip="{content: 'CSDN'}"
			style="
				color: rgb(199,29,35);
				background-color: rgba(199,29,35,.1);
			"
		>
			<i
				class="nexmoefont icon-csdn"
			></i> </a
		><a
			class="mdui-ripple"
			href="https://www.cnblogs.com/lovetangyuxian/"
			target="_blank"
			mdui-tooltip="{content: '博客园'}"
			style="
				color: rgb(66, 214, 29);
				background-color: rgba(66, 214, 29, .1);
			"
		>
			<i
				class="nexmoefont icon-bokeyuan"
			></i> </a
		><a
			class="mdui-ripple"
			href="https://github.com/tangyuxian/"
			target="_blank"
			mdui-tooltip="{content: 'GitHub'}"
			style="
				color: rgb(25, 23, 23);
				background-color: rgba(25, 23, 23, .15);
			"
		>
			<i
				class="nexmoefont icon-github"
			></i> </a
		><a
			class="mdui-ripple"
			href="https://gitee.com/tangyuxian"
			target="_blank"
			mdui-tooltip="{content: 'gitee'}"
			style="
				color: rgb(255, 255, 255);
				background-color: rgb(199,29,35);
			"
		>
			<i
				class="nexmoefont icon-mayun"
			></i> </a
		>
	</div>
</div>

    
        
        
  <div class="nexmoe-widget-wrap">
    <h3 class="nexmoe-widget-title">文章分类</h3>
    <div class="nexmoe-widget">

      <ul class="category-list">

        


        

        

        <li class="category-list-item">
          <a class="category-list-link" href="/categories/其它/">其它</a>
          <span class="category-list-count">2</span>
        </li>

        

        <li class="category-list-item">
          <a class="category-list-link" href="/categories/前端/">前端</a>
          <span class="category-list-count">62</span>
        </li>

        

        <li class="category-list-item">
          <a class="category-list-link" href="/categories/后端/">后端</a>
          <span class="category-list-count">8</span>
        </li>

        

        <li class="category-list-item">
          <a class="category-list-link" href="/categories/开发工具/">开发工具</a>
          <span class="category-list-count">11</span>
        </li>

        

        <li class="category-list-item">
          <a class="category-list-link" href="/categories/服务器端/">服务器端</a>
          <span class="category-list-count">1</span>
        </li>

        
      </ul>

    </div>
  </div>


    
        
        
  <div class="nexmoe-widget-wrap">
    <div id="randomtagcloud" class="nexmoe-widget tagcloud nexmoe-rainbow">
      <a href="/tags/JavaScript/" style="font-size: 15.56px;">JavaScript</a> <a href="/tags/Jetbrains/" style="font-size: 10px;">Jetbrains</a> <a href="/tags/TypeScript/" style="font-size: 10px;">TypeScript</a> <a href="/tags/UI%E5%BA%93/" style="font-size: 13.33px;">UI库</a> <a href="/tags/centos/" style="font-size: 10px;">centos</a> <a href="/tags/css/" style="font-size: 11.11px;">css</a> <a href="/tags/docker/" style="font-size: 10px;">docker</a> <a href="/tags/echarts/" style="font-size: 10px;">echarts</a> <a href="/tags/elementPlus/" style="font-size: 13.33px;">elementPlus</a> <a href="/tags/es6/" style="font-size: 14.44px;">es6</a> <a href="/tags/git/" style="font-size: 13.33px;">git</a> <a href="/tags/github/" style="font-size: 10px;">github</a> <a href="/tags/html/" style="font-size: 10px;">html</a> <a href="/tags/http/" style="font-size: 13.33px;">http</a> <a href="/tags/java/" style="font-size: 11.11px;">java</a> <a href="/tags/markerdown/" style="font-size: 11.11px;">markerdown</a> <a href="/tags/nginx/" style="font-size: 10px;">nginx</a> <a href="/tags/node/" style="font-size: 13.33px;">node</a> <a href="/tags/vite/" style="font-size: 10px;">vite</a> <a href="/tags/vue/" style="font-size: 18.89px;">vue</a> <a href="/tags/webpack/" style="font-size: 10px;">webpack</a> <a href="/tags/xuex/" style="font-size: 10px;">xuex</a> <a href="/tags/%E4%BA%8B%E4%BB%B6%E6%B5%81/" style="font-size: 10px;">事件流</a> <a href="/tags/%E4%BA%92%E8%81%94%E7%BD%91/" style="font-size: 10px;">互联网</a> <a href="/tags/%E5%8A%A0%E5%AF%86/" style="font-size: 12.22px;">加密</a> <a href="/tags/%E5%8E%9F%E5%88%9B/" style="font-size: 20px;">原创</a> <a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size: 13.33px;">工具</a> <a href="/tags/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/" style="font-size: 12.22px;">微信小程序</a> <a href="/tags/%E6%80%BB%E7%BB%93/" style="font-size: 13.33px;">总结</a> <a href="/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/" style="font-size: 10px;">数据结构</a> <a href="/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/" style="font-size: 10px;">服务器</a> <a href="/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/" style="font-size: 17.78px;">浏览器</a> <a href="/tags/%E7%AE%97%E6%B3%95/" style="font-size: 14.44px;">算法</a> <a href="/tags/%E7%BC%96%E8%A7%A3%E7%A0%81/" style="font-size: 10px;">编解码</a> <a href="/tags/%E7%BE%8E%E5%8C%96/" style="font-size: 12.22px;">美化</a> <a href="/tags/%E8%A7%86%E9%A2%91/" style="font-size: 11.11px;">视频</a> <a href="/tags/%E8%AE%B0%E5%BD%95/" style="font-size: 11.11px;">记录</a> <a href="/tags/%E8%BD%AC%E8%BD%BD/" style="font-size: 16.67px;">转载</a>
    </div>
    
      <script>
        var maxTagcloud = parseInt(17);
        var tags_length = parseInt(38);
        var tags_arr = [];
        for(var i = 0; i < tags_length; i++){
          tags_arr.push(i);
        }
        tags_arr.sort(function (l, r) {
          return Math.random() > 0.5 ? -1 : 1;
        });
        tags_arr = tags_arr.slice(0, maxTagcloud < tags_length ? tags_length - maxTagcloud : 0);
        for(var tag_i = 0; tag_i < tags_arr.length; tag_i++){
          document.getElementById("randomtagcloud").children[tags_arr[tag_i]].style.display = 'none';
        }
      </script>
    
  </div>

    
        
        
        
  <div class="nexmoe-widget-wrap">
    <h3 class="nexmoe-widget-title">文章归档</h3>
    <div class="nexmoe-widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2025/">2025</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2023/">2023</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2022/">2022</a><span class="archive-list-count">23</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/">2021</a><span class="archive-list-count">54</span></li></ul>
    </div>
  </div>



    
        
        
  <div class="nexmoe-widget-wrap">
    <h3 class="nexmoe-widget-title">最新文章</h3>
    <div class="nexmoe-widget">
      <ul>
        
          <li>
            <a href="/2025/11/12/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/%E7%BE%8E%E5%8C%96/%E7%BE%8E%E5%8C%96-%E7%BD%91%E9%A1%B5%E4%B8%BB%E9%A2%98%E5%88%87%E6%8D%A2%E7%9A%84%E6%B8%90%E5%8F%98%E5%8A%A8%E7%94%BB/">美化-网页主题切换的渐变动画</a>
          </li>
        
          <li>
            <a href="/2025/09/29/%E5%89%8D%E7%AB%AF/css/css-%E8%A1%A8%E6%A0%BCtd%E4%B8%8B%E9%AB%98%E5%BA%A6%E4%B8%A2%E5%A4%B1%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/">css-表格td下高度丢失解决办法</a>
          </li>
        
          <li>
            <a href="/2025/09/23/%E5%89%8D%E7%AB%AF/vue/vue-%E5%B0%81%E8%A3%85%E5%87%BD%E6%95%B0%E5%BC%8F%E8%A7%A6%E5%8F%91%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95/">vue-封装函数式触发右键菜单组件</a>
          </li>
        
          <li>
            <a href="/2025/06/04/%E5%89%8D%E7%AB%AF/UI%E5%BA%93/UI%E5%BA%93-ElTooltip%E5%8F%AA%E5%9C%A8%E6%96%87%E5%AD%97%E8%B6%85%E5%87%BA%E8%8C%83%E5%9B%B4%E6%97%B6%E6%98%BE%E7%A4%BA%E7%9A%84%E8%A7%86%E7%BA%BF%E6%96%B9%E5%BC%8F/">UI库-ElTooltip只在文字超出范围时显示的视线方式</a>
          </li>
        
          <li>
            <a href="/2025/05/29/%E5%89%8D%E7%AB%AF/UI%E5%BA%93/UI%E5%BA%93-%E5%B0%81%E8%A3%85PageTable%E6%80%BB%E8%A7%88/">UI库-封装PageTable总览</a>
          </li>
        
      </ul>
    </div>
  </div>

    
        
        <div class="nexmoe-widget-wrap">
    <div class="nexmoe-widget nexmoe-link">
		<ul>
        
            <li>
                <a href="https://tangyuxian.com/" target="_blank" >
                    <img src="https://cdn.tangyuxian.com/PicGoImages/202304272004917.jpg" alt="糖糖第一可爱"></img>
                    <p style="color: var(--color-primary)">糖糖第一可爱</p>
                </a>
            </li>
        
		</ul>
    </div>
</div>
<style>
.nexmoe-widget-wrap .nexmoe-link ul li a {
    text-align : center;
}
.nexmoe-widget-wrap .nexmoe-link ul li a img {
    max-width : 100%;
}
.nexmoe-widget-wrap .nexmoe-link ul li a p {
    margin: 10px 0;
}
</style>

    
   
    <div class="nexmoe-copyright">
        &copy; 2025 tangyuxian
        Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
        & <a href="https://github.com/tangyuxian/hexo-theme-tangyuxian" target="_blank">Tangyuxian</a>
        <br><a target="_blank" href="https://beian.miit.gov.cn/">辽ICP备2021002341号</a>
<div style="font-size: 12px">
   <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
   本站总访问量  <a id="busuanzi_value_site_pv"></a> 次<br />
   本站访客数<a id="busuanzi_value_site_uv"></a>人次
</div>

    </div>
</div><!-- .nexmoe-drawer --></div><div id="nexmoe-content"><div class="nexmoe-primary"><div class="nexmoe-post">
  <article>
    
        <div class="nexmoe-post-cover">
            <img src="/images/post/vue.jpg" alt="vue-事件绑定原理" loading="lazy">
            <h1>vue-事件绑定原理</h1>
        </div>
        
    
    <div class="nexmoe-post-meta">
    <div class="nexmoe-rainbow">
        <a class="nexmoefont icon-calendar-fill">2021年03月02日</a>
        
            <a class="nexmoefont icon-appstore-fill -link" href="/categories/%E5%89%8D%E7%AB%AF/">前端</a>
        
        
    </div>
    
    
    
    
    
</div>

    <p>Vue中通过v-on或其语法糖@指令来给元素绑定事件并且提供了事件修饰符</p>
<span id="more"></span>

<p><code>Vue</code>中通过<code>v-on</code>或其语法糖<code>@</code>指令来给元素绑定事件并且提供了事件修饰符，基本流程是进行模板编译生成<code>AST</code>，生成<code>render</code>函数后并执行得到<code>VNode</code>，<code>VNode</code>生成真实<code>DOM</code>节点或者组件时候使用<code>addEventListener</code>方法进行事件绑定。</p>
<h2 id="描述"><a href="#描述" class="headerlink" title="描述"></a>描述</h2><p><code>v-on</code>与<code>@</code>用于绑定事件监听器，事件类型由参数指定，表达式可以是一个方法的名字或一个内联语句，如果没有修饰符也可以省略，用在普通元素上时，只能监听原生<code>DOM</code>事件，用在自定义元素组件上时，也可以监听子组件触发的自定义事件，在监听原生<code>DOM</code>事件时，方法以事件为唯一的参数，如果使用内联语句，语句可以访问一个<code>$event property：v-on:click=&quot;handle(&#39;param&#39;, $event)&quot;</code>，自<code>2.4.0</code>开始<code>v-on</code>同样支持不带参数绑定一个事件或监听器键值对的对象，注意当使用对象语法时，是不支持任何修饰器的。</p>
<h3 id="修饰符"><a href="#修饰符" class="headerlink" title="修饰符"></a>修饰符</h3><ul>
<li><code>.stop</code>: 调用<code>event.stopPropagation()</code>，即阻止事件冒泡。</li>
<li><code>.prevent</code>: 调用<code>event.preventDefault()</code>，即阻止默认事件。</li>
<li><code>.capture</code>: 添加事件侦听器时使用<code>capture</code>模式，即使用事件捕获模式处理事件。</li>
<li><code>.self</code>: 只当事件是从侦听器绑定的元素本身触发时才触发回调。</li>
<li><code>.&#123;keyCode | keyAlias&#125;</code>: 只当事件是从特定键触发时才触发回调。</li>
<li><code>.native</code>: 监听组件根元素的原生事件，即注册组件根元素的原生事件而不是组件自定义事件的。</li>
<li><code>.once</code>: 只触发一次回调。</li>
<li><code>.left(2.2.0)</code>: 只当点击鼠标左键时触发。</li>
<li><code>.right(2.2.0)</code>: 只当点击鼠标右键时触发。</li>
<li><code>.middle(2.2.0)</code>: 只当点击鼠标中键时触发。</li>
<li><code>.passive(2.3.0)</code>: 以<code>&#123; passive: true &#125;</code>模式添加侦听器，表示<code>listener</code>永远不会调用<code>preventDefault()</code>。</li>
</ul>
<h3 id="普通元素"><a href="#普通元素" class="headerlink" title="普通元素"></a>普通元素</h3><figure class="shiki html"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">&lt;!-- 方法处理器 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">v-on:click</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 动态事件 (2.6.0+) --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">v-on:[event]</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 内联语句 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">v-on:click</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThat(&#39;param&#39;, $event)&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 缩写 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@click</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 动态事件缩写 (2.6.0+) --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@[event]</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 停止冒泡 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@click.stop</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 阻止默认行为 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@click.prevent</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 阻止默认行为，没有表达式 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">form</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@submit.prevent</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">form</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!--  串联修饰符 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@click.stop.prevent</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 键修饰符，键别名 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">input</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@keyup.enter</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;onEnter&quot;</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 键修饰符，键代码 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">input</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@keyup.13</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;onEnter&quot;</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 点击回调只会触发一次 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">v-on:click.once</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;doThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 对象语法 (2.4.0+) --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">v-on</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;{ mousedown: doThis, mouseup: doThat }&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">button</span><span style="color: #E1E4E8">&gt;</span></span></code></pre></div></div></figure>

<h3 id="组件元素"><a href="#组件元素" class="headerlink" title="组件元素"></a>组件元素</h3><figure class="shiki html"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">&lt;!-- 自定义事件 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">my-component</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@my-event</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;handleThis&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">my-component</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 内联语句 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">my-component</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@my-event</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;handleThis(&#39;param&#39;, $event)&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">my-component</span><span style="color: #E1E4E8">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">&lt;!-- 组件中的原生事件 --&gt;</span></span>
<span class="line"><span style="color: #E1E4E8">&lt;</span><span style="color: #85E89D">my-component</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">@click.native</span><span style="color: #E1E4E8">=</span><span style="color: #9ECBFF">&quot;onClick&quot;</span><span style="color: #E1E4E8">&gt;&lt;/</span><span style="color: #85E89D">my-component</span><span style="color: #E1E4E8">&gt;</span></span></code></pre></div></div></figure>

<h2 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h2><p><code>Vue</code>源码的实现比较复杂，会处理各种兼容问题与异常以及各种条件分支，文章分析比较核心的代码部分，精简过后的版本，重要部分做出注释，<code>commit id</code>为<code>ef56410</code>。</p>
<h3 id="编译阶段"><a href="#编译阶段" class="headerlink" title="编译阶段"></a>编译阶段</h3><p><code>Vue</code>在挂载实例前，有相当多的工作是进行模板的编译，将<code>template</code>模板进行编译，解析成<code>AST</code>树，再转换成<code>render</code>函数，而在编译阶段，就是对事件的指令做收集处理。<br>在<code>template</code>模板中，定义事件的部分是属于<code>XML</code>的<code>Attribute</code>，所以收集指令时需要匹配<code>Attributes</code>以确定哪个<code>Attribute</code>是属于事件。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #E1E4E8">Copy</span><span style="color: #6A737D">// dev/src/compiler/parser/index.js line 23</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">onRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #DBEDFF">@</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">v-on:</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">dirRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> process.env.</span><span style="color: #79B8FF">VBIND_PROP_SHORTHAND</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">?</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #DBEDFF">v-</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">@</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">:</span><span style="color: #F97583">|^</span><span style="color: #85E89D; font-weight: bold">\.</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">#</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">:</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #DBEDFF">v-</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">@</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">:</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">#</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">dynamicArgRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #85E89D; font-weight: bold">\[</span><span style="color: #79B8FF">.</span><span style="color: #F97583">*</span><span style="color: #85E89D; font-weight: bold">\]</span><span style="color: #F97583">$</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">bindRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #DBEDFF">:</span><span style="color: #F97583">|^</span><span style="color: #85E89D; font-weight: bold">\.</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">v-bind:</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #E1E4E8">  </span></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/parser/index.js line 757</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">processAttrs</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">el</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">list</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> el.attrsList</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> i, l, name, rawName, value, modifiers, syncGen, isDynamic</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">for</span><span style="color: #E1E4E8"> (i </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">0</span><span style="color: #E1E4E8">, l </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> list.</span><span style="color: #79B8FF">length</span><span style="color: #E1E4E8">; i </span><span style="color: #F97583">&lt;</span><span style="color: #E1E4E8"> l; i</span><span style="color: #F97583">++</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">    name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> rawName </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> list[i].name</span></span>
<span class="line"><span style="color: #E1E4E8">    value </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> list[i].value</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (dirRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(name)) { </span><span style="color: #6A737D">// 匹配指令属性</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// mark element as dynamic</span></span>
<span class="line"><span style="color: #E1E4E8">      el.hasBindings </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">true</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// modifiers</span></span>
<span class="line"><span style="color: #E1E4E8">      modifiers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">parseModifiers</span><span style="color: #E1E4E8">(name.</span><span style="color: #B392F0">replace</span><span style="color: #E1E4E8">(dirRE, </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #E1E4E8">)) </span><span style="color: #6A737D">// 将修饰符解析</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// support .foo shorthand syntax for the .prop modifier</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (process.env.</span><span style="color: #79B8FF">VBIND_PROP_SHORTHAND</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> propBindRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(name)) {</span></span>
<span class="line"><span style="color: #E1E4E8">        (modifiers </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> (modifiers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> {})).prop </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">true</span></span>
<span class="line"><span style="color: #E1E4E8">        name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`.`</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span><span style="color: #E1E4E8"> name.</span><span style="color: #B392F0">slice</span><span style="color: #E1E4E8">(</span><span style="color: #79B8FF">1</span><span style="color: #E1E4E8">).</span><span style="color: #B392F0">replace</span><span style="color: #E1E4E8">(modifierRE, </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">      } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers) {</span></span>
<span class="line"><span style="color: #E1E4E8">        name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> name.</span><span style="color: #B392F0">replace</span><span style="color: #E1E4E8">(modifierRE, </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (bindRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(name)) { </span><span style="color: #6A737D">// v-bind // 处理v-bind的情况</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">      } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (onRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(name)) { </span><span style="color: #6A737D">// v-on // 处理事件绑定</span></span>
<span class="line"><span style="color: #E1E4E8">        name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> name.</span><span style="color: #B392F0">replace</span><span style="color: #E1E4E8">(onRE, </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #E1E4E8">) </span><span style="color: #6A737D">// 将事件名匹配</span></span>
<span class="line"><span style="color: #E1E4E8">        isDynamic </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> dynamicArgRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(name) </span><span style="color: #6A737D">// 动态事件绑定</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (isDynamic) { </span><span style="color: #6A737D">// 如果是动态事件</span></span>
<span class="line"><span style="color: #E1E4E8">          name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> name.</span><span style="color: #B392F0">slice</span><span style="color: #E1E4E8">(</span><span style="color: #79B8FF">1</span><span style="color: #E1E4E8">, </span><span style="color: #F97583">-</span><span style="color: #79B8FF">1</span><span style="color: #E1E4E8">) </span><span style="color: #6A737D">// 去掉两端的 []</span></span>
<span class="line"><span style="color: #E1E4E8">        }</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #B392F0">addHandler</span><span style="color: #E1E4E8">(el, name, value, modifiers, </span><span style="color: #79B8FF">false</span><span style="color: #E1E4E8">, warn, list[i], isDynamic) </span><span style="color: #6A737D">// 处理事件收集</span></span>
<span class="line"><span style="color: #E1E4E8">      } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> { </span><span style="color: #6A737D">// normal directives // 处理其他指令</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// literal attribute // 处理文字属性</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<p>通过<code>addHandler</code>方法，为<code>AST</code>树添加事件相关的属性以及对事件修饰符进行处理。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">// dev/src/compiler/helpers.js line 69</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">addHandler</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">el</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTElement</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">name</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">value</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">modifiers</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">?</span><span style="color: #B392F0">ASTModifiers</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">important</span><span style="color: #F97583">?:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">boolean</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">warn</span><span style="color: #F97583">?:</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">?</span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">range</span><span style="color: #F97583">?:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Range</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">dynamic</span><span style="color: #F97583">?:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">boolean</span></span>
<span class="line"><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  modifiers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> modifiers </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> emptyObject</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// passive 和 prevent 不能同时使用，具体是由passive模式的性质决定的</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 详细可以参阅 https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// warn prevent and passive modifier</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">/* istanbul ignore if */</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">    process.env.</span><span style="color: #79B8FF">NODE_ENV</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">!==</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;production&#39;</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> warn </span><span style="color: #F97583">&amp;&amp;</span></span>
<span class="line"><span style="color: #E1E4E8">    modifiers.prevent </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> modifiers.passive</span></span>
<span class="line"><span style="color: #E1E4E8">  ) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #B392F0">warn</span><span style="color: #E1E4E8">(</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #9ECBFF">&#39;passive and prevent can</span><span style="color: #79B8FF">\&#39;</span><span style="color: #9ECBFF">t be used together. &#39;</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #9ECBFF">&#39;Passive handler can</span><span style="color: #79B8FF">\&#39;</span><span style="color: #9ECBFF">t prevent default event.&#39;</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">      range</span></span>
<span class="line"><span style="color: #E1E4E8">    )</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 标准化click.right和click.middle，因为它们实际上不会触发。</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 从技术上讲，这是特定于浏览器的，但是至少目前来说，浏览器是唯一具有右键/中间点击的目标环境。</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// normalize click.right and click.middle since they don&#39;t actually fire</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// this is technically browser-specific, but at least for now browsers are</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// the only target envs that have right/middle clicks.</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers.right) { </span><span style="color: #6A737D">// 将鼠标右键点击标准化 右键点击默认的是 contextmenu 事件</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (dynamic) { </span><span style="color: #6A737D">// 如果是动态事件</span></span>
<span class="line"><span style="color: #E1E4E8">      name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`(${</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">})===&#39;click&#39;?&#39;contextmenu&#39;:(${</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">})`</span><span style="color: #E1E4E8"> </span><span style="color: #6A737D">// 动态确定事件名</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (name </span><span style="color: #F97583">===</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;click&#39;</span><span style="color: #E1E4E8">) { </span><span style="color: #6A737D">// 如果不是动态事件且是鼠标右击</span></span>
<span class="line"><span style="color: #E1E4E8">      name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;contextmenu&#39;</span><span style="color: #E1E4E8"> </span><span style="color: #6A737D">// 则直接替换为contextmenu事件</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">delete</span><span style="color: #E1E4E8"> modifiers.right </span><span style="color: #6A737D">// 删除modifiers的right属性</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers.middle) { </span><span style="color: #6A737D">// 同样标准化处理鼠标中键点击的事件</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (dynamic) { </span><span style="color: #6A737D">// 如果是动态事件</span></span>
<span class="line"><span style="color: #E1E4E8">      name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`(${</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">})===&#39;click&#39;?&#39;mouseup&#39;:(${</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">})`</span><span style="color: #E1E4E8"> </span><span style="color: #6A737D">// 动态确定事件名</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (name </span><span style="color: #F97583">===</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;click&#39;</span><span style="color: #E1E4E8">) { </span><span style="color: #6A737D">// 如果不是动态事件且是鼠标中键点击</span></span>
<span class="line"><span style="color: #E1E4E8">      name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;mouseup&#39;</span><span style="color: #E1E4E8"> </span><span style="color: #6A737D">// 处理为mouseup事件</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 下面是对捕获、一次触发、passive模式的modifiers处理，主要是为事件添加 !、~、&amp; 标记</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 这一部分标记可以在Vue官方文档中查阅 </span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// https://cn.vuejs.org/v2/guide/render-function.html#%E4%BA%8B%E4%BB%B6-amp-%E6%8C%89%E9%94%AE%E4%BF%AE%E9%A5%B0%E7%AC%A6</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// check capture modifier</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers.capture) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">delete</span><span style="color: #E1E4E8"> modifiers.capture</span></span>
<span class="line"><span style="color: #E1E4E8">    name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">prependModifierMarker</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">&#39;!&#39;</span><span style="color: #E1E4E8">, name, dynamic)</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers.once) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">delete</span><span style="color: #E1E4E8"> modifiers.once</span></span>
<span class="line"><span style="color: #E1E4E8">    name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">prependModifierMarker</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">&#39;~&#39;</span><span style="color: #E1E4E8">, name, dynamic)</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">/* istanbul ignore if */</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers.passive) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">delete</span><span style="color: #E1E4E8"> modifiers.passive</span></span>
<span class="line"><span style="color: #E1E4E8">    name </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">prependModifierMarker</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">&#39;&amp;&#39;</span><span style="color: #E1E4E8">, name, dynamic)</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// events 用来记录绑定的事件</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> events</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers.native) { </span><span style="color: #6A737D">// 如果是要触发根元素原生事件则直接取得nativeEvents</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">delete</span><span style="color: #E1E4E8"> modifiers.native</span></span>
<span class="line"><span style="color: #E1E4E8">    events </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> el.nativeEvents </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> (el.nativeEvents </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> {})</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> { </span><span style="color: #6A737D">// 否则取得events</span></span>
<span class="line"><span style="color: #E1E4E8">    events </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> el.events </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> (el.events </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> {})</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 将事件处理函数作为handler</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">newHandler</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">any</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">rangeSetItem</span><span style="color: #E1E4E8">({ value: value.</span><span style="color: #B392F0">trim</span><span style="color: #E1E4E8">(), dynamic }, range)</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifiers </span><span style="color: #F97583">!==</span><span style="color: #E1E4E8"> emptyObject) {</span></span>
<span class="line"><span style="color: #E1E4E8">    newHandler.modifiers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> modifiers</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E1E4E8"> </span><span style="color: #6A737D">// 绑定的事件可以多个，回调也可以多个，最终会合并到数组中</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">handlers</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> events[name]</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">/* istanbul ignore if */</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (Array.</span><span style="color: #B392F0">isArray</span><span style="color: #E1E4E8">(handlers)) {</span></span>
<span class="line"><span style="color: #E1E4E8">    important </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> handlers.</span><span style="color: #B392F0">unshift</span><span style="color: #E1E4E8">(newHandler) </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> handlers.</span><span style="color: #B392F0">push</span><span style="color: #E1E4E8">(newHandler)</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (handlers) {</span></span>
<span class="line"><span style="color: #E1E4E8">    events[name] </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> important </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> [newHandler, handlers] </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> [handlers, newHandler]</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">    events[name] </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> newHandler</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E1E4E8">  el.plain </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">false</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<h3 id="代码生成"><a href="#代码生成" class="headerlink" title="代码生成"></a>代码生成</h3><p>接下来需要将<code>AST</code>语法树转<code>render</code>函数，在这个过程中会加入对事件的处理，首先模块导出了<code>generate</code>函数，<code>generate</code>函数即会返回<code>render</code>字符串，在这之前会调用<code>genElement</code>函数，而在上述<code>addHandler</code>方法处理的最后执行了<code>el.plain = false</code>，这样在<code>genElement</code>函数中会调用<code>genData</code>函数，而在<code>genData</code>函数中即会调用<code>genHandlers</code>函数。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/index.js line 42</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">generate</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">ast</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTElement</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">|</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">void</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">options</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">CompilerOptions</span></span>
<span class="line"><span style="color: #E1E4E8">)</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">CodegenResult</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">state</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">new</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">CodegenState</span><span style="color: #E1E4E8">(options)</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">code</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> ast </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genElement</span><span style="color: #E1E4E8">(ast, state) </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;_c(&quot;div&quot;)&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">    render: </span><span style="color: #9ECBFF">`with(this){return ${</span><span style="color: #E1E4E8">code</span><span style="color: #9ECBFF">}}`</span><span style="color: #E1E4E8">, </span><span style="color: #6A737D">// 即render字符串</span></span>
<span class="line"><span style="color: #E1E4E8">    staticRenderFns: state.staticRenderFns</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/index.js line 55</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genElement</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">el</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTElement</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">state</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">CodegenState</span><span style="color: #E1E4E8">)</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> code</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (el.component) {</span></span>
<span class="line"><span style="color: #E1E4E8">      code </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genComponent</span><span style="color: #E1E4E8">(el.component, el, state)</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> data</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #F97583">!</span><span style="color: #E1E4E8">el.plain </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> (el.pre </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> state.</span><span style="color: #B392F0">maybeComponent</span><span style="color: #E1E4E8">(el))) {</span></span>
<span class="line"><span style="color: #E1E4E8">        data </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genData</span><span style="color: #E1E4E8">(el, state)</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">children</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> el.inlineTemplate </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">null</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genChildren</span><span style="color: #E1E4E8">(el, state, </span><span style="color: #79B8FF">true</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">      code </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`_c(&#39;${</span><span style="color: #E1E4E8">el</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">tag</span><span style="color: #9ECBFF">}&#39;${</span></span>
<span class="line"><span style="color: #9ECBFF">        </span><span style="color: #E1E4E8">data</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">?</span><span style="color: #9ECBFF"> </span><span style="color: #9ECBFF">`,${</span><span style="color: #E1E4E8">data</span><span style="color: #9ECBFF">}`</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">:</span><span style="color: #9ECBFF"> </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #9ECBFF"> </span><span style="color: #6A737D">// data</span></span>
<span class="line"><span style="color: #9ECBFF">      </span><span style="color: #9ECBFF">}${</span></span>
<span class="line"><span style="color: #9ECBFF">        </span><span style="color: #E1E4E8">children</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">?</span><span style="color: #9ECBFF"> </span><span style="color: #9ECBFF">`,${</span><span style="color: #E1E4E8">children</span><span style="color: #9ECBFF">}`</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">:</span><span style="color: #9ECBFF"> </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #9ECBFF"> </span><span style="color: #6A737D">// children</span></span>
<span class="line"><span style="color: #9ECBFF">      </span><span style="color: #9ECBFF">})`</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/index.js line 219</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genData</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">el</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTElement</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">state</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">CodegenState</span><span style="color: #E1E4E8">)</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> data </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;{&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// event handlers</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (el.events) {</span></span>
<span class="line"><span style="color: #E1E4E8">    data </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`${</span><span style="color: #B392F0">genHandlers</span><span style="color: #9ECBFF">(</span><span style="color: #E1E4E8">el</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">events</span><span style="color: #9ECBFF">, </span><span style="color: #79B8FF">false</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">},`</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (el.nativeEvents) {</span></span>
<span class="line"><span style="color: #E1E4E8">    data </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`${</span><span style="color: #B392F0">genHandlers</span><span style="color: #9ECBFF">(</span><span style="color: #E1E4E8">el</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">nativeEvents</span><span style="color: #9ECBFF">, </span><span style="color: #79B8FF">true</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">},`</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">  data </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> data.</span><span style="color: #B392F0">replace</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">/</span><span style="color: #DBEDFF">,</span><span style="color: #F97583">$</span><span style="color: #9ECBFF">/</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #E1E4E8">) </span><span style="color: #F97583">+</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;}&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> data</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/to-function.js line 12 </span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">createFunction</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">code</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">errors</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">try</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">new</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">(code) </span><span style="color: #6A737D">// 将render字符串转为render函数</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">catch</span><span style="color: #E1E4E8"> (err) {</span></span>
<span class="line"><span style="color: #E1E4E8">    errors.</span><span style="color: #B392F0">push</span><span style="color: #E1E4E8">({ err, code })</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> noop</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<p>可以看到无论是处理普通元素事件还是组件根元素原生事件都会调用<code>genHandlers</code>函数，<code>genHandlers</code>函数即会遍历解析好的<code>AST</code>树中事件属性，拿到<code>event</code>对象属性，并根据属性上的事件对象拼接成字符串。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/events.js line 3</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">fnExpRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #DBEDFF">(</span><span style="color: #79B8FF">[\w$_]</span><span style="color: #F97583">+|</span><span style="color: #85E89D; font-weight: bold">\(</span><span style="color: #79B8FF">[</span><span style="color: #F97583">^</span><span style="color: #79B8FF">)]</span><span style="color: #F97583">*?</span><span style="color: #85E89D; font-weight: bold">\)</span><span style="color: #DBEDFF">)</span><span style="color: #79B8FF">\s</span><span style="color: #F97583">*</span><span style="color: #DBEDFF">=&gt;</span><span style="color: #F97583">|^</span><span style="color: #DBEDFF">function(?:</span><span style="color: #79B8FF">\s</span><span style="color: #F97583">+</span><span style="color: #79B8FF">[\w$]</span><span style="color: #F97583">+</span><span style="color: #DBEDFF">)</span><span style="color: #F97583">?</span><span style="color: #79B8FF">\s</span><span style="color: #F97583">*</span><span style="color: #85E89D; font-weight: bold">\(</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">fnInvokeRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #85E89D; font-weight: bold">\(</span><span style="color: #79B8FF">[</span><span style="color: #F97583">^</span><span style="color: #79B8FF">)]</span><span style="color: #F97583">*?</span><span style="color: #85E89D; font-weight: bold">\)</span><span style="color: #DBEDFF">;</span><span style="color: #F97583">*$</span><span style="color: #9ECBFF">/</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">simplePathRE</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #DBEDFF"> </span><span style="color: #9ECBFF">/</span><span style="color: #F97583">^</span><span style="color: #79B8FF">[A-Za-z_$][\w$]</span><span style="color: #F97583">*</span><span style="color: #DBEDFF">(?:</span><span style="color: #85E89D; font-weight: bold">\.</span><span style="color: #79B8FF">[A-Za-z_$][\w$]</span><span style="color: #F97583">*|</span><span style="color: #85E89D; font-weight: bold">\[</span><span style="color: #DBEDFF">&#39;</span><span style="color: #79B8FF">[</span><span style="color: #F97583">^</span><span style="color: #79B8FF">&#39;]</span><span style="color: #F97583">*?</span><span style="color: #DBEDFF">&#39;]</span><span style="color: #F97583">|</span><span style="color: #85E89D; font-weight: bold">\[</span><span style="color: #DBEDFF">&quot;</span><span style="color: #79B8FF">[</span><span style="color: #F97583">^</span><span style="color: #79B8FF">&quot;]</span><span style="color: #F97583">*?</span><span style="color: #DBEDFF">&quot;]</span><span style="color: #F97583">|</span><span style="color: #85E89D; font-weight: bold">\[</span><span style="color: #79B8FF">\d</span><span style="color: #F97583">+</span><span style="color: #DBEDFF">]</span><span style="color: #F97583">|</span><span style="color: #85E89D; font-weight: bold">\[</span><span style="color: #79B8FF">[A-Za-z_$][\w$]</span><span style="color: #F97583">*</span><span style="color: #DBEDFF">])</span><span style="color: #F97583">*$</span><span style="color: #9ECBFF">/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/events.js line 7</span></span>
<span class="line"><span style="color: #6A737D">// KeyboardEvent.keyCode aliases</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">keyCodes</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> { [</span><span style="color: #FFAB70">key</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">]</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">number</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">|</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Array</span><span style="color: #E1E4E8">&lt;</span><span style="color: #79B8FF">number</span><span style="color: #E1E4E8">&gt; } </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  esc: </span><span style="color: #79B8FF">27</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  tab: </span><span style="color: #79B8FF">9</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  enter: </span><span style="color: #79B8FF">13</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  space: </span><span style="color: #79B8FF">32</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  up: </span><span style="color: #79B8FF">38</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  left: </span><span style="color: #79B8FF">37</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  right: </span><span style="color: #79B8FF">39</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  down: </span><span style="color: #79B8FF">40</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #9ECBFF">&#39;delete&#39;</span><span style="color: #E1E4E8">: [</span><span style="color: #79B8FF">8</span><span style="color: #E1E4E8">, </span><span style="color: #79B8FF">46</span><span style="color: #E1E4E8">]</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"><span style="color: #6A737D">// KeyboardEvent.key aliases</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">keyNames</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> { [</span><span style="color: #FFAB70">key</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">]</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">|</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Array</span><span style="color: #E1E4E8">&lt;</span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">&gt; } </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// #7880: IE11 and Edge use `Esc` for Escape key name.</span></span>
<span class="line"><span style="color: #E1E4E8">  esc: [</span><span style="color: #9ECBFF">&#39;Esc&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;Escape&#39;</span><span style="color: #E1E4E8">],</span></span>
<span class="line"><span style="color: #E1E4E8">  tab: </span><span style="color: #9ECBFF">&#39;Tab&#39;</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  enter: </span><span style="color: #9ECBFF">&#39;Enter&#39;</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// #9112: IE11 uses `Spacebar` for Space key name.</span></span>
<span class="line"><span style="color: #E1E4E8">  space: [</span><span style="color: #9ECBFF">&#39; &#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;Spacebar&#39;</span><span style="color: #E1E4E8">],</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// #7806: IE11 uses key names without `Arrow` prefix for arrow keys.</span></span>
<span class="line"><span style="color: #E1E4E8">  up: [</span><span style="color: #9ECBFF">&#39;Up&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;ArrowUp&#39;</span><span style="color: #E1E4E8">],</span></span>
<span class="line"><span style="color: #E1E4E8">  left: [</span><span style="color: #9ECBFF">&#39;Left&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;ArrowLeft&#39;</span><span style="color: #E1E4E8">],</span></span>
<span class="line"><span style="color: #E1E4E8">  right: [</span><span style="color: #9ECBFF">&#39;Right&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;ArrowRight&#39;</span><span style="color: #E1E4E8">],</span></span>
<span class="line"><span style="color: #E1E4E8">  down: [</span><span style="color: #9ECBFF">&#39;Down&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;ArrowDown&#39;</span><span style="color: #E1E4E8">],</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// #9112: IE11 uses `Del` for Delete key name.</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #9ECBFF">&#39;delete&#39;</span><span style="color: #E1E4E8">: [</span><span style="color: #9ECBFF">&#39;Backspace&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;Delete&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;Del&#39;</span><span style="color: #E1E4E8">]</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/events.js line 37</span></span>
<span class="line"><span style="color: #6A737D">// #4868: modifiers that prevent the execution of the listener</span></span>
<span class="line"><span style="color: #6A737D">// need to explicitly return null so that we can determine whether to remove</span></span>
<span class="line"><span style="color: #6A737D">// the listener for .once</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #FFAB70">condition</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=&gt;</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`if(${</span><span style="color: #E1E4E8">condition</span><span style="color: #9ECBFF">})return null;`</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">modifierCode</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> { [</span><span style="color: #FFAB70">key</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">]</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> } </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  stop: </span><span style="color: #9ECBFF">&#39;$event.stopPropagation();&#39;</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  prevent: </span><span style="color: #9ECBFF">&#39;$event.preventDefault();&#39;</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  self: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`$event.target !== $event.currentTarget`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  ctrl: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`!$event.ctrlKey`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  shift: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`!$event.shiftKey`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  alt: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`!$event.altKey`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  meta: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`!$event.metaKey`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  left: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`&#39;button&#39; in $event &amp;&amp; $event.button !== 0`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  middle: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`&#39;button&#39; in $event &amp;&amp; $event.button !== 1`</span><span style="color: #E1E4E8">),</span></span>
<span class="line"><span style="color: #E1E4E8">  right: </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">`&#39;button&#39; in $event &amp;&amp; $event.button !== 2`</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/events.js line 55</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genHandlers</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">events</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTElementHandlers</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">isNative</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">boolean</span></span>
<span class="line"><span style="color: #E1E4E8">)</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">prefix</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> isNative </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;nativeOn:&#39;</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;on:&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> staticHandlers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">``</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> dynamicHandlers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">``</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">for</span><span style="color: #E1E4E8"> (</span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">name</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">in</span><span style="color: #E1E4E8"> events) { </span><span style="color: #6A737D">// 遍历AST解析后的事件属性</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">handlerCode</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genHandler</span><span style="color: #E1E4E8">(events[name]) </span><span style="color: #6A737D">// 将事件对象转换成可拼接的字符串</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (events[name] </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> events[name].dynamic) {</span></span>
<span class="line"><span style="color: #E1E4E8">      dynamicHandlers </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`${</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">},${</span><span style="color: #E1E4E8">handlerCode</span><span style="color: #9ECBFF">},`</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">      staticHandlers </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`&quot;${</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">}&quot;:${</span><span style="color: #E1E4E8">handlerCode</span><span style="color: #9ECBFF">},`</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  staticHandlers </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`{${</span><span style="color: #E1E4E8">staticHandlers</span><span style="color: #9ECBFF">.</span><span style="color: #B392F0">slice</span><span style="color: #9ECBFF">(</span><span style="color: #79B8FF">0</span><span style="color: #9ECBFF">, </span><span style="color: #F97583">-</span><span style="color: #79B8FF">1</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">}}`</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (dynamicHandlers) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> prefix </span><span style="color: #F97583">+</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`_d(${</span><span style="color: #E1E4E8">staticHandlers</span><span style="color: #9ECBFF">},[${</span><span style="color: #E1E4E8">dynamicHandlers</span><span style="color: #9ECBFF">.</span><span style="color: #B392F0">slice</span><span style="color: #9ECBFF">(</span><span style="color: #79B8FF">0</span><span style="color: #9ECBFF">, </span><span style="color: #F97583">-</span><span style="color: #79B8FF">1</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">}])`</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> prefix </span><span style="color: #F97583">+</span><span style="color: #E1E4E8"> staticHandlers</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/events.js line 96</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genHandler</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">handler</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTElementHandler</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">|</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Array</span><span style="color: #E1E4E8">&lt;</span><span style="color: #B392F0">ASTElementHandler</span><span style="color: #E1E4E8">&gt;)</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #F97583">!</span><span style="color: #E1E4E8">handler) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;function(){}&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 事件绑定可以多个，多个在解析AST树时会以数组的形式存在，如果有多个则会递归调用getHandler方法返回数组。</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (Array.</span><span style="color: #B392F0">isArray</span><span style="color: #E1E4E8">(handler)) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`[${</span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">.</span><span style="color: #B392F0">map</span><span style="color: #9ECBFF">(</span><span style="color: #79B8FF">handler</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">=&gt;</span><span style="color: #9ECBFF"> </span><span style="color: #B392F0">genHandler</span><span style="color: #9ECBFF">(</span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">)).</span><span style="color: #B392F0">join</span><span style="color: #9ECBFF">(</span><span style="color: #9ECBFF">&#39;,&#39;</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">}]`</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">isMethodPath</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> simplePathRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(handler.value) </span><span style="color: #6A737D">// 调用方法为 doThis 型</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">isFunctionExpression</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> fnExpRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(handler.value) </span><span style="color: #6A737D">// 调用方法为 () =&gt; {} or function() {} 型</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">isFunctionInvocation</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> simplePathRE.</span><span style="color: #B392F0">test</span><span style="color: #E1E4E8">(handler.value.</span><span style="color: #B392F0">replace</span><span style="color: #E1E4E8">(fnInvokeRE, </span><span style="color: #9ECBFF">&#39;&#39;</span><span style="color: #E1E4E8">)) </span><span style="color: #6A737D">// 调用方法为 doThis($event) 型</span></span>
<span class="line"></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #F97583">!</span><span style="color: #E1E4E8">handler.modifiers) { </span><span style="color: #6A737D">// 没有修饰符</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (isMethodPath </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> isFunctionExpression) { </span><span style="color: #6A737D">// 符合这两个条件则直接返回</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> handler.value</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">/* istanbul ignore if */</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (__WEEX__ </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> handler.params) {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genWeexHandler</span><span style="color: #E1E4E8">(handler.params, handler.value)</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`function($event){${</span><span style="color: #9ECBFF"> </span><span style="color: #6A737D">// 返回拼接的匿名函数的字符串</span></span>
<span class="line"><span style="color: #9ECBFF">      </span><span style="color: #E1E4E8">isFunctionInvocation</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">?</span><span style="color: #9ECBFF"> </span><span style="color: #9ECBFF">`return ${</span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">value</span><span style="color: #9ECBFF">}`</span><span style="color: #9ECBFF"> </span><span style="color: #F97583">:</span><span style="color: #9ECBFF"> </span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">value</span></span>
<span class="line"><span style="color: #9ECBFF">    </span><span style="color: #9ECBFF">}}`</span><span style="color: #E1E4E8"> </span><span style="color: #6A737D">// inline statement</span></span>
<span class="line"><span style="color: #E1E4E8">  } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> { </span><span style="color: #6A737D">// 处理具有修饰符的情况</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> code </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> genModifierCode </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;&#39;</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">keys</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> []</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">for</span><span style="color: #E1E4E8"> (</span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">key</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">in</span><span style="color: #E1E4E8"> handler.modifiers) {  </span><span style="color: #6A737D">// 遍历modifiers上记录的修饰符</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (modifierCode[key]) {</span></span>
<span class="line"><span style="color: #E1E4E8">        genModifierCode </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> modifierCode[key]  </span><span style="color: #6A737D">// 根据修饰符添加对应js的代码</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// left/right</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (keyCodes[key]) {</span></span>
<span class="line"><span style="color: #E1E4E8">          keys.</span><span style="color: #B392F0">push</span><span style="color: #E1E4E8">(key)</span></span>
<span class="line"><span style="color: #E1E4E8">        }</span></span>
<span class="line"><span style="color: #E1E4E8">      } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (key </span><span style="color: #F97583">===</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;exact&#39;</span><span style="color: #E1E4E8">) { </span><span style="color: #6A737D">// 针对exact的处理</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">modifiers</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">ASTModifiers</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> (handler.modifiers: any)</span></span>
<span class="line"><span style="color: #E1E4E8">        genModifierCode </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genGuard</span><span style="color: #E1E4E8">(</span></span>
<span class="line"><span style="color: #E1E4E8">          [</span><span style="color: #9ECBFF">&#39;ctrl&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;shift&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;alt&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;meta&#39;</span><span style="color: #E1E4E8">]</span></span>
<span class="line"><span style="color: #E1E4E8">            .</span><span style="color: #B392F0">filter</span><span style="color: #E1E4E8">(</span><span style="color: #FFAB70">keyModifier</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=&gt;</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">!</span><span style="color: #E1E4E8">modifiers[keyModifier])</span></span>
<span class="line"><span style="color: #E1E4E8">            .</span><span style="color: #B392F0">map</span><span style="color: #E1E4E8">(</span><span style="color: #FFAB70">keyModifier</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=&gt;</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`$event.${</span><span style="color: #E1E4E8">keyModifier</span><span style="color: #9ECBFF">}Key`</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">            .</span><span style="color: #B392F0">join</span><span style="color: #E1E4E8">(</span><span style="color: #9ECBFF">&#39;||&#39;</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">        )</span></span>
<span class="line"><span style="color: #E1E4E8">      } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">        keys.</span><span style="color: #B392F0">push</span><span style="color: #E1E4E8">(key) </span><span style="color: #6A737D">// 如果修饰符不是以上修饰符，则会添加到keys数组中</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (keys.</span><span style="color: #79B8FF">length</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">      code </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genKeyFilter</span><span style="color: #E1E4E8">(keys) </span><span style="color: #6A737D">// 处理其他修饰符 即keyCodes中定义的修饰符</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">// Make sure modifiers like prevent and stop get executed after key filtering</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (genModifierCode) {</span></span>
<span class="line"><span style="color: #E1E4E8">      code </span><span style="color: #F97583">+=</span><span style="color: #E1E4E8"> genModifierCode</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">// 根据三种不同的书写模板返回不同的字符串</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">handlerCode</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> isMethodPath</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`return ${</span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">value</span><span style="color: #9ECBFF">}($event)`</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> isFunctionExpression</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`return (${</span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">value</span><span style="color: #9ECBFF">})($event)`</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> isFunctionInvocation</span></span>
<span class="line"><span style="color: #E1E4E8">          </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`return ${</span><span style="color: #E1E4E8">handler</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">value</span><span style="color: #9ECBFF">}`</span></span>
<span class="line"><span style="color: #E1E4E8">          </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> handler.value</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">/* istanbul ignore if */</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (__WEEX__ </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> handler.params) {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genWeexHandler</span><span style="color: #E1E4E8">(handler.params, code </span><span style="color: #F97583">+</span><span style="color: #E1E4E8"> handlerCode)</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`function($event){${</span><span style="color: #E1E4E8">code</span><span style="color: #9ECBFF">}${</span><span style="color: #E1E4E8">handlerCode</span><span style="color: #9ECBFF">}}`</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/compiler/codegen/events.js line 175</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">genFilterCode</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">key</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">)</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8"> {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">keyVal</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">parseInt</span><span style="color: #E1E4E8">(key, </span><span style="color: #79B8FF">10</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (keyVal) { </span><span style="color: #6A737D">// 如果key是数字，则直接返回$event.keyCode!==${keyVal}</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">`$event.keyCode!==${</span><span style="color: #E1E4E8">keyVal</span><span style="color: #9ECBFF">}`</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">keyCode</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> keyCodes[key]</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">keyName</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> keyNames[key]</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 返回_k函数，它的第一个参数是$event.keyCode，</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 第二个参数是key的值，</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 第三个参数就是key在keyCodes中对应的数字。</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #9ECBFF">`_k($event.keyCode,`</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #9ECBFF">`${</span><span style="color: #79B8FF">JSON</span><span style="color: #9ECBFF">.</span><span style="color: #B392F0">stringify</span><span style="color: #9ECBFF">(</span><span style="color: #E1E4E8">key</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">},`</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #9ECBFF">`${</span><span style="color: #79B8FF">JSON</span><span style="color: #9ECBFF">.</span><span style="color: #B392F0">stringify</span><span style="color: #9ECBFF">(</span><span style="color: #E1E4E8">keyCode</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">},`</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #9ECBFF">`$event.key,`</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #9ECBFF">`${</span><span style="color: #79B8FF">JSON</span><span style="color: #9ECBFF">.</span><span style="color: #B392F0">stringify</span><span style="color: #9ECBFF">(</span><span style="color: #E1E4E8">keyName</span><span style="color: #9ECBFF">)</span><span style="color: #9ECBFF">}`</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #9ECBFF">`)`</span></span>
<span class="line"><span style="color: #E1E4E8">  )</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<h3 id="事件绑定"><a href="#事件绑定" class="headerlink" title="事件绑定"></a>事件绑定</h3><p>前面介绍了如何编译模板提取事件收集指令以及生成<code>render</code>字符串和<code>render</code>函数，但是事件真正的绑定到<code>DOM</code>上还是离不开事件注册，此阶段就发生在<code>patchVnode</code>过程中，在生成完成<code>VNode</code>后，进行<code>patchVnode</code>过程中创建真实<code>DOM</code>时会进行事件注册的相关钩子处理。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">// dev/src/core/vdom/patch.js line 33</span></span>
<span class="line"><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">hooks</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> [</span><span style="color: #9ECBFF">&#39;create&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;activate&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;update&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;remove&#39;</span><span style="color: #E1E4E8">, </span><span style="color: #9ECBFF">&#39;destroy&#39;</span><span style="color: #E1E4E8">]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/core/vdom/patch.js line 125</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">createElm</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">vnode</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">insertedVnodeQueue</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">parentElm</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">refElm</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">nested</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">ownerArray</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #FFAB70">index</span></span>
<span class="line"><span style="color: #E1E4E8">  ) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isDef</span><span style="color: #E1E4E8">(data)) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #B392F0">invokeCreateHooks</span><span style="color: #E1E4E8">(vnode, insertedVnodeQueue)</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// ...</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/core/vdom/patch.js line 303</span></span>
<span class="line"><span style="color: #6A737D">// 在之前cbs经过处理 </span></span>
<span class="line"><span style="color: #6A737D">// 这里cbs.create包含如下几个回调：</span></span>
<span class="line"><span style="color: #6A737D">// updateAttrs、updateClass、updateDOMListeners、updateDOMProps、updateStyle、update、updateDirectives</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">invokeCreateHooks</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">vnode</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">insertedVnodeQueue</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">for</span><span style="color: #E1E4E8"> (</span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> i </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">0</span><span style="color: #E1E4E8">; i </span><span style="color: #F97583">&lt;</span><span style="color: #E1E4E8"> cbs.create.</span><span style="color: #79B8FF">length</span><span style="color: #E1E4E8">; </span><span style="color: #F97583">++</span><span style="color: #E1E4E8">i) {</span></span>
<span class="line"><span style="color: #E1E4E8">      cbs.create[i](emptyNode, vnode)</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    i </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> vnode.data.hook </span><span style="color: #6A737D">// Reuse variable</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isDef</span><span style="color: #E1E4E8">(i)) {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isDef</span><span style="color: #E1E4E8">(i.create)) i.</span><span style="color: #B392F0">create</span><span style="color: #E1E4E8">(emptyNode, vnode)</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isDef</span><span style="color: #E1E4E8">(i.insert)) insertedVnodeQueue.</span><span style="color: #B392F0">push</span><span style="color: #E1E4E8">(vnode)</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<p><code>invokeCreateHooks</code>就是一个模板指令处理的任务，他分别针对不同的指令为真实阶段创建不同的任务，针对事件，这里会调<code>updateDOMListeners</code>对真实的<code>DOM</code>节点注册事件任务。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">// dev/src/platforms/web/runtime/modules/events.js line 105</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">updateDOMListeners</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">oldVnode</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">VNodeWithData</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">vnode</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">VNodeWithData</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isUndef</span><span style="color: #E1E4E8">(oldVnode.data.on) </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">isUndef</span><span style="color: #E1E4E8">(vnode.data.on)) {  </span><span style="color: #6A737D">// on是事件指令的标志</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">return</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 新旧节点不同的事件绑定解绑</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">on</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> vnode.data.on </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> {}</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">oldOn</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> oldVnode.data.on </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> {}</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 拿到需要添加事件的真实DOM节点</span></span>
<span class="line"><span style="color: #E1E4E8">  target </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> vnode.elm</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// normalizeEvents是对事件兼容性的处理</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">normalizeEvents</span><span style="color: #E1E4E8">(on)</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// 调用updateListeners方法，并将on作为参数传进去</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">updateListeners</span><span style="color: #E1E4E8">(on, oldOn, add, remove, createOnceHandler, vnode.context)</span></span>
<span class="line"><span style="color: #E1E4E8">  target </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">undefined</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/core/vdom/helpers/update-listeners.js line line 53</span></span>
<span class="line"><span style="color: #F97583">export</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">updateListeners</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">on</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Object</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">oldOn</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Object</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">add</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">remove</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">createOnceHandler</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">vm</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Component</span></span>
<span class="line"><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">let</span><span style="color: #E1E4E8"> name, def, cur, old, event</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">for</span><span style="color: #E1E4E8"> (name </span><span style="color: #F97583">in</span><span style="color: #E1E4E8"> on) { </span><span style="color: #6A737D">// 遍历事件</span></span>
<span class="line"><span style="color: #E1E4E8">    def </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> cur </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> on[name]</span></span>
<span class="line"><span style="color: #E1E4E8">    old </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> oldOn[name]</span></span>
<span class="line"><span style="color: #E1E4E8">    event </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">normalizeEvent</span><span style="color: #E1E4E8">(name)</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #6A737D">/* istanbul ignore if */</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (__WEEX__ </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">isPlainObject</span><span style="color: #E1E4E8">(def)) {</span></span>
<span class="line"><span style="color: #E1E4E8">      cur </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> def.handler</span></span>
<span class="line"><span style="color: #E1E4E8">      event.params </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> def.params</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isUndef</span><span style="color: #E1E4E8">(cur)) { </span><span style="color: #6A737D">// 事件名非法的报错处理</span></span>
<span class="line"><span style="color: #E1E4E8">      process.env.</span><span style="color: #79B8FF">NODE_ENV</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">!==</span><span style="color: #E1E4E8"> </span><span style="color: #9ECBFF">&#39;production&#39;</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">&amp;&amp;</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">warn</span><span style="color: #E1E4E8">(</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #9ECBFF">`Invalid handler for event &quot;${</span><span style="color: #E1E4E8">event</span><span style="color: #9ECBFF">.</span><span style="color: #E1E4E8">name</span><span style="color: #9ECBFF">}&quot;: got `</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">+</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">String</span><span style="color: #E1E4E8">(cur),</span></span>
<span class="line"><span style="color: #E1E4E8">        vm</span></span>
<span class="line"><span style="color: #E1E4E8">      )</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isUndef</span><span style="color: #E1E4E8">(old)) { </span><span style="color: #6A737D">// 旧节点不存在</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isUndef</span><span style="color: #E1E4E8">(cur.fns)) { </span><span style="color: #6A737D">// createFunInvoker返回事件最终执行的回调函数</span></span>
<span class="line"><span style="color: #E1E4E8">        cur </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> on[name] </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">createFnInvoker</span><span style="color: #E1E4E8">(cur, vm)</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isTrue</span><span style="color: #E1E4E8">(event.once)) {  </span><span style="color: #6A737D">// 只触发一次的事件</span></span>
<span class="line"><span style="color: #E1E4E8">        cur </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> on[name] </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">createOnceHandler</span><span style="color: #E1E4E8">(event.name, cur, event.capture)</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// 执行真正注册事件的执行函数</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #B392F0">add</span><span style="color: #E1E4E8">(event.name, cur, event.capture, event.passive, event.params)</span></span>
<span class="line"><span style="color: #E1E4E8">    } </span><span style="color: #F97583">else</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (cur </span><span style="color: #F97583">!==</span><span style="color: #E1E4E8"> old) {</span></span>
<span class="line"><span style="color: #E1E4E8">      old.fns </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> cur</span></span>
<span class="line"><span style="color: #E1E4E8">      on[name] </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> old</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">for</span><span style="color: #E1E4E8"> (name </span><span style="color: #F97583">in</span><span style="color: #E1E4E8"> oldOn) { </span><span style="color: #6A737D">// 旧节点存在，解除旧节点上的绑定事件</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span><span style="color: #B392F0">isUndef</span><span style="color: #E1E4E8">(on[name])) {</span></span>
<span class="line"><span style="color: #E1E4E8">      event </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">normalizeEvent</span><span style="color: #E1E4E8">(name)</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #6A737D">// 移除事件监听</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #B392F0">remove</span><span style="color: #E1E4E8">(event.name, oldOn[name], event.capture)</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/platforms/web/runtime/modules/events.js line 32</span></span>
<span class="line"><span style="color: #6A737D">// 在执行完回调之后，移除事件绑定</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">createOnceHandler</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">event</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">handler</span><span style="color: #E1E4E8">, </span><span style="color: #FFAB70">capture</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">_target</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> target </span><span style="color: #6A737D">// save current target element in closure</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">onceHandler</span><span style="color: #E1E4E8"> () {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">res</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> handler.</span><span style="color: #B392F0">apply</span><span style="color: #E1E4E8">(</span><span style="color: #79B8FF">null</span><span style="color: #E1E4E8">, </span><span style="color: #79B8FF">arguments</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (res </span><span style="color: #F97583">!==</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">null</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #B392F0">remove</span><span style="color: #E1E4E8">(event, onceHandler, capture, _target)</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<p>最终添加与移除事件都是调用的<code>add</code>与<code>remove</code>方法，最终调用的方法即<code>DOM</code>的<code>addEventListener</code>方法与<code>removeEventListener</code>方法。</p>
<figure class="shiki javascript"><div class='codeblock'><div class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></div><div class="code"><pre class="shiki github-dark"><code><span class="line"><span style="color: #6A737D">// dev/src/platforms/web/runtime/modules/events.js line 46</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">add</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">name</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">handler</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">capture</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">boolean</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">passive</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">boolean</span></span>
<span class="line"><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// async edge case #6566: inner click event triggers patch, event handler</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// attached to outer element during patch, and triggered again. This</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// happens because browsers fire microtask ticks between event propagation.</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// the solution is simple: we save the timestamp when a handler is attached,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// and the handler would only fire if the event passed to it was fired</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #6A737D">// AFTER it was attached.</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (useMicrotaskFix) {</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">attachedTimestamp</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> currentFlushTimestamp</span></span>
<span class="line"><span style="color: #E1E4E8">    </span><span style="color: #F97583">const</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">original</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> handler</span></span>
<span class="line"><span style="color: #E1E4E8">    handler </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> original.</span><span style="color: #B392F0">_wrapper</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">=</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">function</span><span style="color: #E1E4E8"> (</span><span style="color: #FFAB70">e</span><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">if</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// no bubbling, should always fire.</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// this is just a safety net in case event.timeStamp is unreliable in</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// certain weird environments...</span></span>
<span class="line"><span style="color: #E1E4E8">        e.target </span><span style="color: #F97583">===</span><span style="color: #E1E4E8"> e.currentTarget </span><span style="color: #F97583">||</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// event is fired after handler attachment</span></span>
<span class="line"><span style="color: #E1E4E8">        e.timeStamp </span><span style="color: #F97583">&gt;=</span><span style="color: #E1E4E8"> attachedTimestamp </span><span style="color: #F97583">||</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// bail for environments that have buggy event.timeStamp implementations</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// #9462 iOS 9 bug: event.timeStamp is 0 after history.pushState</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// #9681 QtWebEngine event.timeStamp is negative value</span></span>
<span class="line"><span style="color: #E1E4E8">        e.timeStamp </span><span style="color: #F97583">&lt;=</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">0</span><span style="color: #E1E4E8"> </span><span style="color: #F97583">||</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// #9448 bail if event is fired in another document in a multi-page</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// electron/nw.js app, since event.timeStamp will be using a different</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #6A737D">// starting reference</span></span>
<span class="line"><span style="color: #E1E4E8">        e.target.ownerDocument </span><span style="color: #F97583">!==</span><span style="color: #E1E4E8"> document</span></span>
<span class="line"><span style="color: #E1E4E8">      ) {</span></span>
<span class="line"><span style="color: #E1E4E8">        </span><span style="color: #F97583">return</span><span style="color: #E1E4E8"> original.</span><span style="color: #B392F0">apply</span><span style="color: #E1E4E8">(</span><span style="color: #79B8FF">this</span><span style="color: #E1E4E8">, </span><span style="color: #79B8FF">arguments</span><span style="color: #E1E4E8">)</span></span>
<span class="line"><span style="color: #E1E4E8">      }</span></span>
<span class="line"><span style="color: #E1E4E8">    }</span></span>
<span class="line"><span style="color: #E1E4E8">  }</span></span>
<span class="line"><span style="color: #E1E4E8">  target.</span><span style="color: #B392F0">addEventListener</span><span style="color: #E1E4E8">(</span></span>
<span class="line"><span style="color: #E1E4E8">    name,</span></span>
<span class="line"><span style="color: #E1E4E8">    handler,</span></span>
<span class="line"><span style="color: #E1E4E8">    supportsPassive</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">?</span><span style="color: #E1E4E8"> { capture, passive }</span></span>
<span class="line"><span style="color: #E1E4E8">      </span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> capture</span></span>
<span class="line"><span style="color: #E1E4E8">  )</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A737D">// dev/src/platforms/web/runtime/modules/events.js line 92</span></span>
<span class="line"><span style="color: #F97583">function</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">remove</span><span style="color: #E1E4E8"> (</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">name</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">string</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #B392F0">handler</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">Function</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">capture</span><span style="color: #F97583">:</span><span style="color: #E1E4E8"> </span><span style="color: #79B8FF">boolean</span><span style="color: #E1E4E8">,</span></span>
<span class="line"><span style="color: #E1E4E8">  </span><span style="color: #FFAB70">_target</span><span style="color: #F97583">?:</span><span style="color: #E1E4E8"> </span><span style="color: #B392F0">HTMLElement</span></span>
<span class="line"><span style="color: #E1E4E8">) {</span></span>
<span class="line"><span style="color: #E1E4E8">  (_target </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> target).</span><span style="color: #B392F0">removeEventListener</span><span style="color: #E1E4E8">(</span></span>
<span class="line"><span style="color: #E1E4E8">    name,</span></span>
<span class="line"><span style="color: #E1E4E8">    handler._wrapper </span><span style="color: #F97583">||</span><span style="color: #E1E4E8"> handler,</span></span>
<span class="line"><span style="color: #E1E4E8">    capture</span></span>
<span class="line"><span style="color: #E1E4E8">  )</span></span>
<span class="line"><span style="color: #E1E4E8">}</span></span></code></pre></div></div></figure>

<hr>
<p>参考文档:<a target="_blank" rel="noopener" href="https://www.cnblogs.com/WindrunnerMax/p/13629209.html">博客园文章:Vue事件绑定原理</a></p>

    
  </article>

  
      
    <div class="nexmoe-post-copyright">
        <strong>本文作者：</strong>tangyuxian<br>
        
        <strong>本文链接：</strong><a href="https://www.tangyuxian.com/2021/03/02/%E5%89%8D%E7%AB%AF/vue/vue-%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86/" title="https:&#x2F;&#x2F;www.tangyuxian.com&#x2F;2021&#x2F;03&#x2F;02&#x2F;%E5%89%8D%E7%AB%AF&#x2F;vue&#x2F;vue-%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86&#x2F;" target="_blank" rel="noopener">https:&#x2F;&#x2F;www.tangyuxian.com&#x2F;2021&#x2F;03&#x2F;02&#x2F;%E5%89%8D%E7%AB%AF&#x2F;vue&#x2F;vue-%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86&#x2F;</a><br>

        
            <strong>版权声明：</strong>本文采用 <a href="https://creativecommons.org/licenses/by-nc-sa/3.0/cn/deed.zh" target="_blank">CC BY-NC-SA 3.0 CN</a> 协议进行许可

        
    </div>


  
  
  <div class="nexmoe-post-meta nexmoe-rainbow">
   
    
        <a class="nexmoefont icon-tag-fill -none-link" href="/tags/vue/" rel="tag">vue</a>
    
</div>
  
  
    <script async src="/js/copy-codeblock.js?v=1763992123965"></script>
  

  
      <div class="nexmoe-post-footer">
          <div class="valine"></div>
<script src='https://lib.baomitu.com/valine/1.3.9/Valine.min.js'></script>
<script>
  new Valine({
      el: '.valine',
      appId: 'r5zxC0st0DDjPA9auXzMV7HY-gzGzoHsz',
      appKey: '3bqCsovpyfTPHUzTHovd3V3V'
  })
</script>

      </div>
  
</div></div><div class="nexmoe-post-right">    <div class="nexmoe-fixed">
        <div class="nexmoe-tool">

            

            
            
            <button class="mdui-fab catalog" style="overflow:unset;">
                <i class="nexmoefont icon-i-catalog"></i>
                <div class="nexmoe-toc">
                    <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8F%8F%E8%BF%B0"><span class="toc-number">1.</span> <span class="toc-text">描述</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BF%AE%E9%A5%B0%E7%AC%A6"><span class="toc-number">1.1.</span> <span class="toc-text">修饰符</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%99%AE%E9%80%9A%E5%85%83%E7%B4%A0"><span class="toc-number">1.2.</span> <span class="toc-text">普通元素</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E4%BB%B6%E5%85%83%E7%B4%A0"><span class="toc-number">1.3.</span> <span class="toc-text">组件元素</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%86%E6%9E%90"><span class="toc-number">2.</span> <span class="toc-text">分析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BC%96%E8%AF%91%E9%98%B6%E6%AE%B5"><span class="toc-number">2.1.</span> <span class="toc-text">编译阶段</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90"><span class="toc-number">2.2.</span> <span class="toc-text">代码生成</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A"><span class="toc-number">2.3.</span> <span class="toc-text">事件绑定</span></a></li></ol></li></ol>
                </div>
            </button>
            

            

            <a href="#nexmoe-content" class="backtop toc-link" aria-label="Back To Top" title="top"><button class="mdui-fab mdui-ripple"><i class="nexmoefont icon-caret-top"></i></button></a>
        </div>
    </div>
</div></div><div id="nexmoe-pendant"><div class="nexmoe-drawer mdui-drawer nexmoe-pd" id="drawer">
    
        
            <div class="nexmoe-pd-item">
                <div class="clock">
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="memory"></div>
        <div class="needle" id="hours"></div>
        <div class="needle" id="minutes"></div>
        <div class="needle" id="seconds"></div>
        <div class="clock_logo">

        </div>

    </div>
<script>
        // ----- Variable declaration

        var data = {
                dt: new Date(),
                hours: {
                        el: document.querySelector('#hours'),
                        val: 0 },

                minutes: {
                        el: document.querySelector('#minutes'),
                        val: 0 },

                seconds: {
                        el: document.querySelector('#seconds'),
                        val: 0 },

                renderTime: 1000 };


        // ----- Clock rendering logic

        updateTime = () => {
                let hour = data.dt.getHours();
                let minute = data.dt.getMinutes();
                let second = data.dt.getSeconds();

                data.hours.el.classList.add('moving');
                data.minutes.el.classList.add('moving');
                data.seconds.el.classList.add('moving');

                data.hours.val = hour == 0 && data.hours.val == 59 * 6 * 5 ? 360 : hour * 6 * 5;
                data.minutes.val = minute == 0 && data.minutes.val == 59 * 6 ? 360 : minute * 6;
                data.seconds.val = second == 0 && data.seconds.val == 59 * 6 ? 360 : second * 6;

                data.hours.el.style.transform = `translate(-50%, -75%) rotate(${data.hours.val}deg)`;
                data.minutes.el.style.transform = `translate(-50%, -75%) rotate(${data.minutes.val}deg)`;
                data.seconds.el.style.transform = `translate(-50%, -75%) rotate(${data.seconds.val}deg)`;

                data.dt.setSeconds(second + 1);
        };

        // ----- Clock execution

        setInterval(() => {
                updateTime();
        }, data.renderTime);

        updateTime();

        // ----- Events area

        data.seconds.el.addEventListener('transitionend', () => {
                data.hours.el.classList.remove('moving');
                data.minutes.el.classList.remove('moving');
                data.seconds.el.classList.remove('moving');

                // if (data.hours.val == 360) {
                //   data.hours.el.style.transform = 'translate(-50%, -75%) rotate(0deg)';
                // }

                if (data.minutes.val == 360) {
                        data.minutes.el.style.transform = 'translate(-50%, -75%) rotate(0deg)';
                }

                if (data.seconds.val == 360) {
                        data.seconds.el.style.transform = 'translate(-50%, -75%) rotate(0deg)';
                }
        });

</script>
<style>
    .clock {
        background-color: #ffffff;
        width: 70vw;
        height: 70vw;
        max-width: 70vh;
        max-height: 70vh;
        border: solid 2.8vw var(--color-primary);
        position: relative;
        overflow: hidden;
        border-radius: 50%;
        box-sizing: border-box;
        box-shadow: 0 1.4vw 2.8vw var(--color2);
        zoom:0.2
    }

    .memory {
        position: absolute;
        top: 50%;
        left: 50%;
        transform-origin: center;
    }

    .memory:nth-child(1) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(0deg) translateY(-520%);
    }

    .memory:nth-child(2) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(6deg) translateY(-1461%);
    }

    .memory:nth-child(3) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(12deg) translateY(-1461%);
    }

    .memory:nth-child(4) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(18deg) translateY(-1461%);
    }

    .memory:nth-child(5) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(24deg) translateY(-1461%);
    }

    .memory:nth-child(6) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(30deg) translateY(-520%);
    }

    .memory:nth-child(7) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(36deg) translateY(-1461%);
    }

    .memory:nth-child(8) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(42deg) translateY(-1461%);
    }

    .memory:nth-child(9) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(48deg) translateY(-1461%);
    }

    .memory:nth-child(10) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(54deg) translateY(-1461%);
    }

    .memory:nth-child(11) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(60deg) translateY(-520%);
    }

    .memory:nth-child(12) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(66deg) translateY(-1461%);
    }

    .memory:nth-child(13) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(72deg) translateY(-1461%);
    }

    .memory:nth-child(14) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(78deg) translateY(-1461%);
    }

    .memory:nth-child(15) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(84deg) translateY(-1461%);
    }

    .memory:nth-child(16) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(90deg) translateY(-520%);
    }

    .memory:nth-child(17) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(96deg) translateY(-1461%);
    }

    .memory:nth-child(18) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(102deg) translateY(-1461%);
    }

    .memory:nth-child(19) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(108deg) translateY(-1461%);
    }

    .memory:nth-child(20) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(114deg) translateY(-1461%);
    }

    .memory:nth-child(21) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(120deg) translateY(-520%);
    }

    .memory:nth-child(22) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(126deg) translateY(-1461%);
    }

    .memory:nth-child(23) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(132deg) translateY(-1461%);
    }

    .memory:nth-child(24) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(138deg) translateY(-1461%);
    }

    .memory:nth-child(25) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(144deg) translateY(-1461%);
    }

    .memory:nth-child(26) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(150deg) translateY(-520%);
    }

    .memory:nth-child(27) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(156deg) translateY(-1461%);
    }

    .memory:nth-child(28) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(162deg) translateY(-1461%);
    }

    .memory:nth-child(29) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(168deg) translateY(-1461%);
    }

    .memory:nth-child(30) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(174deg) translateY(-1461%);
    }

    .memory:nth-child(31) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(180deg) translateY(-520%);
    }

    .memory:nth-child(32) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(186deg) translateY(-1461%);
    }

    .memory:nth-child(33) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(192deg) translateY(-1461%);
    }

    .memory:nth-child(34) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(198deg) translateY(-1461%);
    }

    .memory:nth-child(35) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(204deg) translateY(-1461%);
    }

    .memory:nth-child(36) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(210deg) translateY(-520%);
    }

    .memory:nth-child(37) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(216deg) translateY(-1461%);
    }

    .memory:nth-child(38) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(222deg) translateY(-1461%);
    }

    .memory:nth-child(39) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(228deg) translateY(-1461%);
    }

    .memory:nth-child(40) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(234deg) translateY(-1461%);
    }

    .memory:nth-child(41) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(240deg) translateY(-520%);
    }

    .memory:nth-child(42) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(246deg) translateY(-1461%);
    }

    .memory:nth-child(43) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(252deg) translateY(-1461%);
    }

    .memory:nth-child(44) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(258deg) translateY(-1461%);
    }

    .memory:nth-child(45) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(264deg) translateY(-1461%);
    }

    .memory:nth-child(46) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(270deg) translateY(-520%);
    }

    .memory:nth-child(47) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(276deg) translateY(-1461%);
    }

    .memory:nth-child(48) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(282deg) translateY(-1461%);
    }

    .memory:nth-child(49) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(288deg) translateY(-1461%);
    }

    .memory:nth-child(50) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(294deg) translateY(-1461%);
    }

    .memory:nth-child(51) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(300deg) translateY(-520%);
    }

    .memory:nth-child(52) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(306deg) translateY(-1461%);
    }

    .memory:nth-child(53) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(312deg) translateY(-1461%);
    }

    .memory:nth-child(54) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(318deg) translateY(-1461%);
    }

    .memory:nth-child(55) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(324deg) translateY(-1461%);
    }

    .memory:nth-child(56) {
        background-color: var(--color-primary);
        width: 2%;
        height: 8%;
        transform: translate(-50%, -50%) rotate(330deg) translateY(-520%);
    }

    .memory:nth-child(57) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(336deg) translateY(-1461%);
    }

    .memory:nth-child(58) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(342deg) translateY(-1461%);
    }

    .memory:nth-child(59) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(348deg) translateY(-1461%);
    }

    .memory:nth-child(60) {
        background-color: #949494;
        width: 1%;
        height: 3%;
        transform: translate(-50%, -50%) rotate(354deg) translateY(-1461%);
    }

    .needle {
        position: absolute;
        top: 50%;
        left: 50%;
        transform-origin: center;
    }

    .needle#hours {
        background-color: #1f1f1f;
        width: 4%;
        height: 30%;
        transform-origin: center 75%;
        transform: translate(-50%, -75%);
    }

    .needle#hours.moving {
        transition: transform 150ms ease-out;
    }

    .needle#hours:after {
        content: '';
        background-color: #1f1f1f;
        width: 4vw;
        height: 4vw;
        max-width: 4vh;
        max-height: 4vh;
        display: block;
        position: absolute;
        top: 75%;
        left: 50%;
        box-sizing: border-box;
        border-radius: 50%;
        transform: translate(-50%, -50%);
    }

    .needle#minutes {
        background-color: #1f1f1f;
        width: 2%;
        height: 45%;
        transform-origin: center 75%;
        transform: translate(-50%, -75%);
    }

    .needle#minutes.moving {
        transition: transform 150ms ease-out;
    }

    .needle#minutes:after {
        content: '';
        background-color: #1f1f1f;
        width: 4vw;
        height: 4vw;
        max-width: 4vh;
        max-height: 4vh;
        display: block;
        position: absolute;
        top: 75%;
        left: 50%;
        box-sizing: border-box;
        border-radius: 50%;
        transform: translate(-50%, -50%);
    }

    .needle#seconds {
        background-color: #cb2f2f;
        width: 1%;
        height: 50%;
        transform-origin: center 75%;
        transform: translate(-50%, -75%);
    }

    .needle#seconds.moving {
        transition: transform 150ms ease-out;
    }

    .needle#seconds:after {
        content: '';
        background-color: #cb2f2f;
        width: 2.5vw;
        height: 2.5vw;
        max-width: 2.5vh;
        max-height: 2.5vh;
        display: block;
        position: absolute;
        top: 75%;
        left: 50%;
        box-sizing: border-box;
        border-radius: 50%;
        transform: translate(-50%, -50%);
    }
    .clock_logo{
        width: 10vw;
        height: 10vw;
        max-width: 10vh;
        max-height: 10vh;
        position: absolute;
        top: 50%;
        left: 50%;
        box-sizing: border-box;
        border-radius: 50%;
        transform: translate(-50%, -50%);
        background-size: 100% 100%;
        background-repeat: no-repeat;
    }
    .clock_logo{
            width: 10vw;
            height: 10vw;
            max-width: 10vh;
            max-height: 10vh;
            position: absolute;
            top: 50%;
            left: 50%;
            box-sizing: border-box;
            border-radius: 50%;
            transform: translate(-50%, -50%);
            background-image: var(--clock-logo);
            background-size: 100% 100%;
            background-repeat: no-repeat;
    }
    @media (min-width: 100vh) {
        .clock {
            border: solid 2.8vh var(--color-primary);
            box-shadow: 0 1.4vh 2.8vh var(--color2);
        }
    }

</style>





            </div>
        
            <div class="nexmoe-pd-item">
                <div class="qweather" >
    <div id="he-plugin-standard">
        <iframe allowtransparency="true" frameborder="0" width="304" height="96" scrolling="no" src="//tianqi.2345.com/plugin/widget/index.htm?s=2&z=1&t=0&v=0&d=2&bd=0&k=000000&f=ff8040&ltf=009944&htf=cc0000&q=1&e=1&a=1&c=54511&w=300&h=96&align=center"></iframe>
    </div>
    <div class="qweather-logo">

    </div>
</div>
<style>
    .qweather{
        position: relative;
        padding-right: 5px;
    }
    .qweather #he-plugin-standard {
        border: 2px solid var(--color-primary);
        box-shadow: 0 1px 0 0 var(--color-primary), 0 1px 2px 0 var(--color-primary);
        border-radius: 8px;
        width: 300px;
        overflow: hidden;
    }
    .qweather-logo{
        position: absolute;
        right: 0;
        top: -15px;
        width: 40px;
        height: 40px;
        background-image: var(--qweather-logo);
        background-size: 100% 100%;
        background-repeat: no-repeat;
    }
</style>

            </div>
        
    
</div>
<style>
    .nexmoe-pd {
        left: auto;
        top: 40px;
        right: 0;
    }
    .nexmoe-pd-item{
       display: flex;
        justify-content: center;
        margin-bottom: 30px;
    }
    #nexmoe-pendant .mdui-drawer{
        width: 305px;
    }
    @media screen and (max-width: 1600px) {
        #nexmoe-pendant {
            display: none
        }
    }
</style>
</div><div id="nexmoe-footer"><!--!--></div><div id="nexmoe-search-space"><div class="search-container"><div class="search-header"><div class="search-input-container"><input class="search-input" type="text" placeholder="搜索" onInput="sinput();"></div><a class="search-close" onclick="sclose();">×</a></div><div class="search-body"></div></div></div><div></div><!-- hexo injector body_end start -->
<script src="https://cdn.jsdelivr.net/npm/hexo-shiki-plugin@latest/lib/codeblock.js"></script>

  <script>
  const CODE_CONFIG = {
    beautify: true,
    highlightCopy: true,
    highlightLang: true,
    highlightHeightLimit: null,
    isHighlightShrink: false,
    copy: {
      success: 'Copy Success',
      error: 'Copy Error',
      noSupport: 'Browser Not Support',
    }
  };
  console.log(
    `%c hexo-shiki-plugin %c v1.0.27 %c https://github.com/nova1751/hexo-shiki-plugin`,
    "color: #fff; background: #5f5f5f",
    "color: #fff; background: #80c8f8",
    ""
  );
  </script>
  <!-- hexo injector body_end end --><script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"model":{"jsonPath":"/live2dw/assets/xiaomai.model.json"},"display":{"position":"left","width":200,"height":500},"mobile":{"show":false},"react":{"opacity":0.9},"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body></html>